package ru.maksb.exchange.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.SocketException;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.maksb.exchange.exceptions.ExchangeException;
import ru.maksb.exchange.service.ExchangeWorker;

public class Server {
    private static final String PROPERTIES_PATH = "src/main/resources/exchange.properties";
    private final static Logger logger = LoggerFactory.getLogger(Server.class);
    private int port;
    private int backlog;
    private SocketHandler socketHanler;
    private ServerSocket serverSocket;
    private ExchangeWorker exchange;
    private AtomicBoolean serverIsRunnung = new AtomicBoolean();

    public Server(int port, int backlog, SocketHandler socketHanler) {
        this.port = port;
        this.backlog = backlog;
        this.socketHanler = socketHanler;
        exchange = new ExchangeWorker(PROPERTIES_PATH);
    }

    /**
     * Method opens ServerSocket, starts listen port.
     * For each <code>serverSocket.accept()</code> method calls 
     * <code>socketHanler.handle(socket)</code>  
     * @throws ExchangeException
     */
    public void start() throws ExchangeException {
        logger.info("Starting exchange server on {} port", port);
        serverIsRunnung.set(true);
        try {
            logger.debug("Opening serverSocket on {} port", port);
            serverSocket = new ServerSocket(port, backlog);
            logger.debug("serverSocket opened");
        } catch (IOException e1) {
            logger.error("serverSocket opening failed");
            throw new ExchangeException("Cannot start server", e1);
        }
        
        logger.debug("Starting exchange worker thread");
        new Thread(exchange).start(); 
        
        try {
            logger.info("Start listen port");
            while (serverIsRunnung.get()) {
                socketHanler.handle(serverSocket.accept(), exchange);
            }
        } catch (SocketException e) {
            // перестаем слушать порт
        } catch (IOException e) {
            throw new ExchangeException("Cannot listen port. Restart server", e);
        } finally {
            shutdown();
        }
    }
    
    public void shutdown() throws ExchangeException {
        try {
            logger.info("Shutdowning server");
            serverSocket.close();
            logger.info("Server shutdowned");
        } catch (IOException e) {
            logger.error("Error while server shutdown", e);
            throw new ExchangeException("Cannot shutdown server", e);
        }
    }
    
    public static void main(String[] args) {
        Server server = new Server(1234, 0, new SocketHandler());
        try {
            server.start();
        } catch (ExchangeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
